﻿using PSE.Framework.Communication.Adapters;
using PSE.Framework.Communication.Configuration.Adapters;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Diagnostics;
using PSE.Framework.Communication.Messages;
using TGPInterfaceParam;
using PSE.Framework.Communication.Adapters.Tgp;
using PSE.Framework.Communication.Configuration.Tgp;
using System.IO;
using System.Xml.Serialization;
using PSE.Framework.Communication.Configuration.Adapters.Tgp;

namespace PSE.Framework.Communication.Adapters.Tgp
{
    public class TgpInputAdapter : SyncInputAdapter<TgpInputConfiguration, TgpOpenParameter, TgpReceiveParameter>
    {
        private TGPExecutorNet.TGPExecutor _tgpExecutor;
        private TgpCommon _common;
        private TgpOpenParameter _openParameter;
        private Dictionary<string, XmlSerializer> _serializers;

        public TgpInputAdapter()
        {
        }

        protected override object Deserialize(object message, string action)
        {
            object deserializedMessage = message;

            if (_serializers.ContainsKey(action))
            {
                if (message is TgpResponseMessage)
                {
                    StringReader reader = new StringReader(System.Convert.ToString(((TgpResponseMessage)message).Mensagem));

                    ((TgpResponseMessage)message).Mensagem = _serializers[action].Deserialize(reader);
                }
                else
                {
                    foreach (TgpResponseMessage msg in (IList)message)
                    {
                        StringReader reader = new StringReader(System.Convert.ToString(msg.Mensagem));

                        msg.Mensagem = _serializers[action].Deserialize(reader);
                    }
                }

                deserializedMessage = message;
            }

            return deserializedMessage;
        }

        public override MessageInfo Receive(TgpReceiveParameter parameter)
        {
            if (parameter == null)
                throw new ArgumentNullException("parameter");

            this.VerifyIsOpened();

            ParametroSaida parametroSaida;
            ParametroEntrada parametroEntrada = new TGPInterfaceParam.ParametroEntrada();
            parametroEntrada.InstituicaoOrigem = this._openParameter.InstituicaoOrigem;
            parametroEntrada.InstituicaoDestino = this._openParameter.InstituicaoDestino;
            parametroEntrada.Usuario = this._openParameter.Usuario;
            parametroEntrada.Sistema = this._openParameter.Sistema;
            parametroEntrada.TipoComando = TGPInterfaceParam.TipoComando.TCGetMsg;

            if (parameter.ReceberColecao)
                _tgpExecutor.Executa(parametroEntrada, out parametroSaida);
            else
                _tgpExecutor.ExecutaV2(parametroEntrada, out parametroSaida);

            TGPInterfaceParam.ColRespMensagem colRespMsg = parametroSaida.ColRespMensagem;

            if (colRespMsg.Count == 0)
                throw new InvalidOperationException("Invalid response, ColRespMensagem is empty");

            object msg;

            if (parameter.ReceberColecao)
            {
                List<TgpResponseMessage> responses = new List<TgpResponseMessage>();

                foreach (RespMensagem tgpResponse in colRespMsg)
                {
                    TgpResponseMessage response = new TgpResponseMessage();

                    response.InstituicaoOrigem = tgpResponse.InstituicaoOrigem;
                    response.InstituicaoDestino = tgpResponse.InstituicaoDestino;
                    response.NumeroOperacao = tgpResponse.Nuop;
                    response.CodigoMensagemServidor = tgpResponse.CodMsgServer;

                    response.IdMensagem = tgpResponse.MsgId;
                    response.Mensagem = tgpResponse.Mensagem;
                    response.Sistema = tgpResponse.Sistema;
                    response.Usuario = tgpResponse.Usuario;

                    response.TipoMensagem = (TgpMessageType)(int)tgpResponse.TipoMensagem;

                    responses.Add(response);
                }

                msg = responses;
            }
            else
            {
                RespMensagem tgpResponse = colRespMsg[0];

                TgpResponseMessage response = new TgpResponseMessage();

                response.InstituicaoOrigem = tgpResponse.InstituicaoOrigem;
                response.InstituicaoDestino = tgpResponse.InstituicaoDestino;
                response.NumeroOperacao = tgpResponse.Nuop;
                response.CodigoMensagemServidor = tgpResponse.CodMsgServer;

                response.IdMensagem = tgpResponse.MsgId;
                response.Mensagem = tgpResponse.Mensagem;
                response.Sistema = tgpResponse.Sistema;
                response.Usuario = tgpResponse.Usuario;

                response.TipoMensagem = (TgpMessageType)(int)tgpResponse.TipoMensagem;

                msg = response;
            }

            return this.ProcessAndDeliveryMessage(msg);
        }

        public override void Open(TgpInputConfiguration config, TgpOpenParameter parameter)
        {
            if (config == null)
                throw new ArgumentNullException("config");
            if (parameter == null)
                throw new ArgumentNullException("parameter");

            this.VerifyIsCreated();

            _serializers = new Dictionary<string, XmlSerializer>();

            foreach (TgpInputAdapterActionConfiguration action in config.Actions)
                if (action.DeserializedMessageType != null)
                    _serializers.Add(action.Name, new XmlSerializer(action.DeserializedMessageType));

            _tgpExecutor = new TGPExecutorNet.TGPExecutor();
            _openParameter = parameter;
            _common = new TgpCommon(_tgpExecutor, _openParameter, config.AuthenticationRetry, config.AuthenticationRetryWait);
            _common.Open();

            base.Open(config, parameter);
        }

        public override void Close()
        {
            this.VerifyIsOpened();

            _common.Close();

            base.Close();
        }

        #region SendEchoMessage
        /// <summary>
        /// Envia mensagem de eco
        /// </summary>
        /// <returns>Código da mensagem</returns>
        public int SendEchoMessage()
        {
            this.VerifyIsOpened();

            return _common.SendEchoMessage();
        }
        #endregion

        #region GetEchoMessageStatus
        /// <summary>
        /// Captura o status da mensagem de eco
        /// </summary>
        /// <param name="codigoMensagem">Código da mensagem</param>
        /// <returns>Status da mensagem</returns>
        public TgpMessageStatus GetEchoMessageStatus(int codigoMensagem)
        {
            this.VerifyIsOpened();

            return _common.GetEchoMessageStatus(codigoMensagem);
        }
        #endregion
    }
}
